package com.seleniti.enpareja.web.desktop.server.model.integration.service.impl.appengine;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.ioc.commons.utils.jdo.JdoQueryHelper;
import org.ioc.commons.utils.logs.Log4JFormatterLogger;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Transaction;
import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.common.exception.EnParejaException;
import com.seleniti.enpareja.controller.common.exception.EnParejaException.ErrorCode;
import com.seleniti.enpareja.controller.model.integration.database.domain.Couple;
import com.seleniti.enpareja.controller.model.integration.database.domain.CoupleType;
import com.seleniti.enpareja.controller.model.integration.database.domain.Food;

public class GAEAdminService extends GAEService {
	/**
	 * Logger for this class
	 */
	private static final Log4JFormatterLogger logger = Log4JFormatterLogger.getLogger(GAEAdminService.class);

	public GAEAdminService() {
		logger.info("GAE Admin management service instance");
	}

	public void fixInconsistentValues() {

		logger.info("Fixing inconsistent values...");

		/*
		 * 1.- All couples with default type
		 */

		JdoQueryHelper q1 = JdoQueryHelper.newQuery(pm, Couple.class);

		logger.info("All couples with default type...");

		List<Couple> couples = (List<Couple>) q1.execute();
		int fixed1 = 0;
		int fixed2 = 0;
		if (couples != null) {
			for (Couple c : couples) {
				if (c.getCoupleType() == null) {
					fixed1++;
					c.setCoupleType(CoupleType.USERS_COUPLE);
				}

				Set<Date> dates = new HashSet<>();
				Set<Food> toRemove = new HashSet<>();
				List<Food> meals = c.getFoods();
				if (meals != null) {
					for (Food m : meals) {
						Date d = m.getDate();
						if (dates.contains(d)) {
							fixed2++;
							toRemove.add(m);
						} else {
							dates.add(d);
						}
					}
				}

				if (!toRemove.isEmpty()) {
					pm.deletePersistentAll(toRemove);
				}
			}
		}

		logger.info(fixed1 == 0 && fixed2==0, "...all couples OK");
		logger.info(fixed1 > 0, "... fixed empty couple type " + fixed1);
		logger.info(fixed2 > 0, "... fixed duplicate dates " + fixed2);

	}

	public void removeNoneElementsFromList() throws EnParejaException {
		LoggedUserInfo lui = assertLoggedIn("Remove all null elements from list");

		if (!lui.isAdmin()) {
			throw new EnParejaException(ErrorCode.PERMISSION_DENIED, "You must be an admin user to perform this action");
		}

		String entity = "Couple";
		String listProperty = "shoppingListElements";

		// Get the Datastore Service
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

		// Filter noneFilter = new FilterPredicate(listProperty,
		// FilterOperator.EQUAL, null);

		Query q = new Query(entity);// .setFilter(noneFilter);

		// Use PreparedQuery interface to retrieve results
		PreparedQuery pq = datastore.prepare(q);

		for (Entity result : pq.asIterable()) {
			boolean requiresUpdate = false;
			List<Object> newValue = new ArrayList<Object>();
			List<?> value = (List<?>) result.getProperty(listProperty);

			if (value != null) {
				for (Iterator<?> it = value.iterator(); it.hasNext();) {
					Object elm = it.next();

					if (elm != null) {
						newValue.add(elm);
					} else {
						requiresUpdate = true;
						logger.info("Couple {0} requires update!", result);
					}
				}
			}

			if (requiresUpdate) {
				Transaction tx = datastore.beginTransaction();

				logger.debug("Prev value: {0}\n\nNew value: {1}\n", value, newValue);

				result.setProperty(listProperty, newValue);

				datastore.put(tx, result);

				tx.commit();

				logger.debug("After commit: {0}", result);

			}
		}

	}
}
